package jvm.jtacck.db;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.sql.SQLException;

import jvm.jtacck.AndroidServer;
import jvm.jtacck.db.records.*;
import jvm.jtacck.serials.Route;

import static jvm.jtacck.Util.*;

/**
 * AwesomeCoreHandler(ACH) represents an interface over the PostgresHandler. The
 * purpose of ACH is to provide a useful interface to the servers so that data
 * can be sent as Strings and ints rather than the Record objects used by the
 * PostgresHandler. This interface also provides, in addition to the general
 * getters, more specific getters that have been specially tailored to the needs
 * of the server.
 * 
 * @author Andrew Lau
 * 
 * @see jvm.jtacck.db.PostgresHandler
 * 
 */
public final class AwesomeCoreHandler {

	/**
	 * A list of Android servers that can be used.
	 */
	private final static List<AndroidServer> server = new LinkedList<AndroidServer>();

	/**
	 * The handler used to connect to the database.
	 */
	private static PostgresHandler dbConnection = null;

	/**
	 * A filler variable used for variables that are automatically generated.
	 */
	private final static int FILLER = 1;

	/**
	 * Adds an Android Server to the current list of servers.
	 * 
	 * @param serv
	 *            - reference to an Android Server.
	 */
	synchronized public static void setServer(AndroidServer serv) {
		if (serv != null && !server.contains(serv)) {
			server.add(serv);
		}
	}

	/**
	 * Attempts to create a new connection to the database with the given
	 * username, password, and database address.
	 * 
	 * @param username
	 *            - username for the PostgresHandler
	 * @param password
	 *            - password that corresponds to the username.
	 * @param dbAddress
	 *            - address of the database. Must be of the format
	 *            [server]:[port]/[databasename].
	 * 
	 * @return Returns true if a connection to the database has been made.
	 *         Otherwise, returns false.
	 */
	public static boolean createConnection(String username, String password,
			String dbAddress) {
		try {
			dbConnection = new PostgresHandler(username, password, dbAddress);
			return true;
		} catch (SQLException e) {
			logger.info("Connection to database couldn't be made");
			return false;
		}
	}

	/**
	 * Attempts to close the connection with the database.
	 * 
	 * @return Returns true if the connection to the database has been closed.
	 *         Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 */
	public static boolean closeConnection() throws IllegalStateException {
		noConnection();
		try {
			dbConnection.close();
			return true;
		} catch (SQLException e) {
			logger.info("Connection to database already closed");
			return false;
		}
	}

	// ----------------------------------------------------------------------------
	// Methods that add to the database
	// ----------------------------------------------------------------------------

	/**
	 * Attempts to add a client site to the database.
	 * 
	 * @param name
	 *            - name of the client site
	 * @param hospital
	 *            - the id of hospital associated to the client site.
	 * @param instructions
	 *            - instructions of what to do at the client site. Intended for
	 *            couriers
	 * @param phone
	 *            - phone number of the client site
	 * 
	 * @returns Returns true if the addition to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean addClientSite(String name, int hospital_id,
			List<String> instructions, String phone)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		Hospital hospital = getHospital(hospital_id);

		if (noNulls(hospital, instructions, phone, name) && lengthChecker(name)) {
			try {
				dbConnection.addRecord(new ClientSite(FILLER, name, hospital,
						instructions, phone));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException(
					"One or more arguments were null or name was too short");
		}
	}

	/**
	 * Attempts to add a courier to the database.
	 * 
	 * @param username
	 *            - the username of the user who is being assigned as a courier
	 * @param password
	 *            - the password assigned to the username
	 * @param first
	 *            - the first name of the person
	 * @param last
	 *            - the last name of the person
	 * @param site_id
	 *            - the id of the client site the person is assigned to
	 * @param type_id
	 *            - the id of the type the person is
	 * @param client_id_route
	 *            - the id of client sites of the route the courier is assigned
	 *            to
	 * @param lat
	 *            - The latitude of the current user based on the Android GPS
	 * @param longit
	 *            - The longitude of the current user based on the Android GPS
	 * 
	 * @returns Returns true if the addition to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean addCourier(String username, String password,
			String first, String last, int site_id, int type_id,
			List<Integer> client_id_route) throws IllegalStateException,
			IllegalArgumentException {

		noConnection();

		if (client_id_route != null) {

			List<ClientSite> temp = new LinkedList<ClientSite>();

			for (Integer i : client_id_route) {
				if (getClientSite(i) == null) {
					throw new IllegalArgumentException("Invalid destination "
							+ i);
				}
				temp.add(getClientSite(i));
			}

			try {
				dbConnection.addRecord(new Courier(new User(username, password,
						first, last, getClientSite(site_id),
						getUserType(type_id)), temp, 0, 0,
						temp.size() == 0 ? null : temp.get(0)));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("Route or username is null.");
		}
	}

	/**
	 * Attempts to add a hospital to the database.
	 * 
	 * @param name
	 *            - name of the hospital
	 * @param address
	 *            - address of the hospital in the form: [Address 1], [Address
	 *            2], [City], [State], [ZipCode]
	 * 
	 * @returns Returns true if the addition to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if the parameters are invalid
	 */
	public static boolean addHospital(String name, String address)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		if (noNulls(name, address) && lengthChecker(name, address)) {
			try {
				dbConnection.addRecord(new Hospital(FILLER, name, address));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("Name or address is invalid");
		}
	}

	/**
	 * Adds an item to the given specimen. Use this to add a item to the
	 * existing item collection of a specimen.
	 * 
	 * @param barcode
	 *            - barcode of the specimen
	 * @param name
	 *            - name of the item
	 * @param color
	 *            - color of the item (or its cap)
	 * 
	 * @return Returns true if the modification to the database was successful.
	 *         Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if there is an invalid argument
	 */
	public static boolean addItemToSpecimen(String barcode, String name,
			String color) throws IllegalStateException,
			IllegalArgumentException {
		noConnection();
		if (getShippingInfo(barcode) == null) {
			throw new IllegalArgumentException("Invalid barcode");
		}
		if (noNulls(name, color) && lengthChecker(name, color)
				&& barcode.length() > 0) {
			try {
				Specimen old = dbConnection.getSpecimenByID(barcode);
				Collection<Item> temp = new LinkedList<Item>();
				temp.addAll(old.contents);
				temp.add(new Item(FILLER, name, color));
				Specimen replace = new Specimen(old.barcode, old.description,
						old.requirements, temp);
				dbConnection.changeRecord(replace);
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException(
					"Name or color is invalid or barcode is less than 0.");
		}
	}

	/**
	 * Attempts to add a Status into the database.
	 * 
	 * @param name
	 *            - the name of the status
	 * @param desc
	 *            - the description of the status
	 * 
	 * @return Returns true if addition was successful. Otherwise, returns
	 *         false.
	 * 
	 * @throws IllegalStateException
	 *             if there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if the parameters are invalid
	 */
	public static boolean addStatus(String name, String desc)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		if (noNulls(name, desc) && lengthChecker(name, desc)) {
			try {
				dbConnection.addRecord(new Status(FILLER, name, desc));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("Name or description is invalid");
		}

	}

	/**
	 * Attempts to add shipping information to the database.
	 * 
	 * @param barcode
	 *            - a barcode used to identify the specimen
	 * @param reqs
	 *            - any requirements associated to the specimen
	 * @param instructions
	 *            - any instructions needed for the specimen
	 * @param items
	 *            - a collection of items within the specimen package
	 * @param username
	 *            - the username of the person adding the specimen info
	 * @param dest
	 *            - an id representing a client site destination
	 * @param status
	 *            - an id representing a status type
	 * 
	 * @returns Returns true if the addition to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if there is an invalid argument
	 */
	public static boolean addShippingInformation(String barcode, String desc,
			String reqs, Map<String, List<String>> items, String username,
			int dest) throws IllegalStateException, IllegalArgumentException {

		noConnection();

		if (getShippingInfo(barcode) != null || items == null) {
			throw new IllegalArgumentException("Duplicate barcode exists"
					+ " or null items");
		}

		Collection<Item> actualItems = new LinkedList<Item>();

		if (!items.isEmpty()) {
			for (String s : items.keySet()) {
				for (String t : items.get(s)) {
					actualItems.add(new Item(FILLER, s, t));
				}
			}
		}

		if (noNulls(reqs, desc, username, getUser(username),
				getClientSite(dest))
				&& !barcode.isEmpty()
				&& !actualItems.isEmpty()) {
			try {
				Specimen s_temp = new Specimen(barcode, desc, reqs, actualItems);
				dbConnection.addRecord(new ShippingInformation(s_temp,
						getUser(username), getClientSite(dest), getStatus(1),
						null));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException(
					"Null strings detected, ivalid username/destination or "
							+ "barcode is less than 1.");
		}
	}

	/**
	 * Attempts to add a user to the database. If the user is of type courier,
	 * then the user will be automatically created a courier record.
	 * 
	 * @param username
	 *            - The username of the person being added
	 * @param password
	 *            - The password associated to the username
	 * @param first
	 *            - The first name of the person
	 * @param last
	 *            - The last name of the person
	 * @param site_id
	 *            - A client site that the person is assigned to
	 * @param type_id
	 *            - A user type regarding the person's privileges
	 * 
	 * @returns Returns true if the addition to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if the arguments are not valid such as being null
	 */
	public static boolean addUser(String username, String password,
			String first, String last, int site_id, int type_id)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		ClientSite cs = getClientSite(site_id);
		UserType type = getUserType(type_id);

		if (noNulls(username, password, first, last, cs, type)
				&& lengthChecker(username, password, first, last)) {

			if (getUser(username) != null) {
				return false;
			}

			try {
				dbConnection.addRecord(new User(username, password, first,
						last, cs, type));
				if (type.type_id == 5) {
					return addCourier(username, password, first, last, site_id,
							type_id, new LinkedList<Integer>());
				}
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("One or more of the parameters"
					+ " are invalid. Input must not be empty.");
		}

	}

	/**
	 * Attempts to add a User Type into the database.
	 * 
	 * @param name
	 *            - the name of the user type
	 * @param desc
	 *            - the description of the user type
	 * 
	 * @return Returns true if addition was successful. Otherwise, returns
	 *         false.
	 * 
	 * @throws IllegalStateException
	 *             if there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if the parameters are invalid
	 */
	public static boolean addUserType(String name, String desc)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		if (noNulls(name, desc) && lengthChecker(name, desc)) {
			try {
				dbConnection.addRecord(new UserType(FILLER, name, desc));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("Name or description is invalid");
		}

	}

	// -------------------------------------------------------------------------
	//
	// Methods that modify items in the database
	//
	// -------------------------------------------------------------------------

	// ////////////////////////////////////////////
	//
	// Check list
	//
	// ////////////////////////////////////////////

	/**
	 * Attempts to modify a check list in the database.
	 * 
	 * @param start
	 *            - the starting check list
	 * @param end
	 *            - the ending check list
	 * 
	 * @return Returns true if modification was successful. Otherwise, returns
	 *         false.
	 * 
	 @throws IllegalStateException
	 *             if the there is no connection to the database
	 */
	public static boolean changeCheckList(List<String> start, List<String> end)
			throws IllegalStateException {

		noConnection();

		CheckListPair temp = getCheckLists();

		try {
			if (start == null) {
				start = temp.startingList;
			}
			if (end == null) {
				end = temp.endingList;
			}
			dbConnection.changeRecord(new CheckListPair(start, end));
			return true;
		} catch (SQLException e) {
			logger.info(e.toString());
			return false;
		}
	}

	/**
	 * Attempts to modify the starting check list. If passed null, will do
	 * nothing.
	 * 
	 * @param start
	 *            - the new starting check list
	 * 
	 * @return Returns true if modification is successful. Otherwise, returns
	 *         false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 */
	public static boolean changeStartingList(List<String> start)
			throws IllegalStateException {
		return start == null || changeCheckList(start, null);
	}

	/**
	 * Attempts to modify the ending check list. If passed null, will do
	 * nothing.
	 * 
	 * @param start
	 *            - the new ending check list
	 * 
	 * @return Returns true if modification is successful. Otherwise, returns
	 *         false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 */
	public static boolean changeEndingList(List<String> end)
			throws IllegalStateException {
		return end == null || changeCheckList(null, end);
	}

	// ////////////////////////////////////////////
	//
	// ClientSite
	//
	// ////////////////////////////////////////////

	/**
	 * Attempts to modify a client site to the database.
	 * 
	 * @param cs_id
	 *            - the id of the client site
	 * @param name
	 *            - name of the client site
	 * @param hospital_id
	 *            - the id of hospital associated to the client site. SHOULD NOT
	 *            BE MODIFIABLE BY END USER.
	 * @param instructions
	 *            - instructions of what to do at the client site. Intended for
	 *            couriers
	 * @param phone
	 *            - phone number of the client site
	 * 
	 * @returns Returns true if the modification to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeClientSite(int cs_id, String name,
			int hospital_id, List<String> instructions, String phone)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		Hospital hospital = getHospital(hospital_id);
		ClientSite cs = getClientSite(cs_id);

		if (noNulls(hospital, cs, instructions, phone, name) && !name.isEmpty()) {
			try {
				dbConnection.changeRecord(new ClientSite(cs_id, name, hospital,
						instructions, phone));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException(
					"One or more arguments were null or name was too short");
		}
	}

	/**
	 * Attempts to modify the name of a client site.
	 * 
	 * @param cs_id
	 *            - the id of the client site
	 * @param name
	 *            - the new name of the client site
	 * 
	 * @return Returns true if modification was successful. Otherwise, false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeClientSiteName(int cs_id, String name)
			throws IllegalStateException, IllegalArgumentException {

		ClientSite temp = getClientSite(cs_id);

		if (temp != null) {
			return changeClientSite(cs_id, name, temp.hospital.hospital_id,
					temp.instructions, temp.phone_number);
		} else {
			return false;
		}
	}

	/**
	 * Attempts to modify check list associated to a client site.
	 * 
	 * @param cs_id
	 *            - the id of the client site
	 * @param instructions
	 *            - instructions of what to do at the client site. Intended for
	 *            couriers
	 * 
	 * @returns Returns true if the modification to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeClientSiteList(int cs_id,
			List<String> instructions) throws IllegalStateException,
			IllegalArgumentException {

		if (noNulls(instructions, getClientSite(cs_id))) {
			ClientSite temp = getClientSite(cs_id);
			return changeClientSite(cs_id, temp.name,
					temp.hospital.hospital_id, instructions, temp.phone_number);
		} else {
			throw new IllegalArgumentException(
					"One or more arguments were null or name was too short");
		}
	}

	/**
	 * Attempts to modify the phone number of a client site.
	 * 
	 * @param cs_id
	 *            - the id of the client site
	 * @param phone
	 *            - the new phone number of the client site
	 * 
	 * @return Returns true if modification was successful. Otherwise, false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeClientSitePhone(int cs_id, String phone)
			throws IllegalStateException, IllegalArgumentException {

		ClientSite temp = getClientSite(cs_id);

		if (temp != null) {
			return changeClientSite(cs_id, temp.name,
					temp.hospital.hospital_id, temp.instructions, phone);
		} else {
			return false;
		}
	}

	// ////////////////////////////////////////////
	//
	// Courier
	//
	// ////////////////////////////////////////////

	/**
	 * Attempts to modify a courier to the database.
	 * 
	 * @param username
	 *            - the username of the user who is being assigned as a courier.
	 *            THIS SHOULD NOT BE MODIFIABLE BY END USER.
	 * @param password
	 *            - the password assigned to the username
	 * @param first
	 *            - the first name of the person
	 * @param last
	 *            - the last name of the person
	 * @param site_id
	 *            - the id of the client site the person is assigned to
	 * @param type_id
	 *            - the id of the type the person is
	 * @param client_id_route
	 *            - the id of client sites of the route the courier is assigned
	 *            to
	 * @param lat
	 *            - The latitude of the current user based on the Android GPS
	 * @param longit
	 *            - The longitude of the current user based on the Android GPS
	 * 
	 * @returns Returns true if the modification to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeCourier(String username, String password,
			String first, String last, int site_id, int type_id,
			List<Integer> client_id_route) throws IllegalStateException,
			IllegalArgumentException {

		noConnection();

		if (noNulls(username, password, first, last, client_id_route,
				getUser(username), getCourierInfo(username))
				&& lengthChecker(username, password, first, last)) {

			List<ClientSite> temp = new LinkedList<ClientSite>();

			for (Integer i : client_id_route) {
				if (getClientSite(i) == null) {
					throw new IllegalArgumentException("Invalid destination "
							+ i);
				}
				temp.add(getClientSite(i));
			}

			Courier old = getCourierInfo(username);
			ClientSite cs = null;
			if ((old.nextDest == null || !temp.contains(old.nextDest))
					&& !temp.isEmpty()) {
				cs = temp.get(0);
			} else if (temp.contains(old.nextDest)) {
				cs = old.nextDest;
			}

			try {
				dbConnection.changeRecord(new Courier(new User(username,
						password, first, last, getClientSite(site_id),
						getUserType(type_id)), temp, old.latitude,
						old.longitude, cs));
				server.get(0).pushRoute(username,
						getRouteWithPackages(username));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("One or more strings are null "
					+ "or of empty length");
		}
	}

	/**
	 * Attempts to modify a route assigned to a courier in the database.
	 * 
	 * @param username
	 *            - the username of the user who is being assigned as a courier.
	 *            THIS SHOULD NOT BE MODIFIABLE BY END USER.
	 * @param client_id_route
	 *            - the id of client sites of the route the courier is assigned
	 *            to
	 * 
	 * @returns Returns true if the modification to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeCourierRoute(String username,
			List<Integer> client_id_route) throws IllegalStateException,
			IllegalArgumentException {

		if (noNulls(username, client_id_route, getCourierInfo(username))) {

			Courier old = getCourierInfo(username);

			return changeCourier(username, old.user.password, old.user.fname,
					old.user.lname, old.user.site.client_id,
					old.user.type.type_id, client_id_route);
		} else {
			throw new IllegalArgumentException("One or more strings are null "
					+ "or of empty length");
		}
	}

	// ////////////////////////////////////////////
	//
	// Hospital
	//
	// ////////////////////////////////////////////

	/**
	 * Attempts to modify a hospital to the database.
	 * 
	 * @param hospital_id
	 *            - id of the hospital being modified. THIS SHOULD NOT BE
	 *            MODIFIABLE BY END USER.
	 * @param name
	 *            - name of the hospital
	 * @param address
	 *            - address of the hospital in the form: [Address 1], [Address
	 *            2], [City], [State], [ZipCode]
	 * 
	 * @returns Returns true if the modification to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if the parameters are invalid
	 */
	public static boolean changeHospital(int hospital_id, String name,
			String address) throws IllegalStateException,
			IllegalArgumentException {

		noConnection();

		Hospital hospital = getHospital(hospital_id);

		if (noNulls(hospital, name, address) && lengthChecker(name, address)) {
			try {
				dbConnection.changeRecord(new Hospital(hospital_id, name,
						address));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("Name or address is invalid");
		}
	}

	/**
	 * Attempts to modify the name of a hospital.
	 * 
	 * @param h_id
	 *            - the id of the hospital
	 * @param name
	 *            - the new name of the hospital
	 * 
	 * @return Returns true if modification was successful. Otherwise, false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeHospitalName(int h_id, String name)
			throws IllegalStateException, IllegalArgumentException {

		Hospital temp = getHospital(h_id);

		if (temp != null) {
			return changeHospital(h_id, name, temp.address);
		} else {
			return false;
		}
	}

	/**
	 * Attempts to modify the address of a hospital.
	 * 
	 * @param h_id
	 *            - the id of the hospital
	 * @param address
	 *            - the new address of the hospital in the form: [Address 1],
	 *            [Address 2], [City], [State], [ZipCode]
	 * 
	 * @return Returns true if modification was successful. Otherwise, false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeHospitalAddress(int h_id, String address)
			throws IllegalStateException, IllegalArgumentException {

		Hospital temp = getHospital(h_id);

		if (temp != null) {
			return changeHospital(h_id, temp.name, address);
		} else {
			return false;
		}
	}

	// ////////////////////////////////////////////
	//
	// Status
	//
	// ////////////////////////////////////////////

	/**
	 * Attempts to modify a status in the database.
	 * 
	 * @param id
	 *            - the id of the status
	 * @param name
	 *            - the name of the status
	 * @param desc
	 *            - the description of the status
	 * 
	 * @return Returns true if modification was successful. Otherwise, returns
	 *         false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeStatus(int id, String name, String desc)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		Status temp = getStatus(id);

		if (noNulls(temp, name, desc) && lengthChecker(name, desc)) {
			try {
				dbConnection.changeRecord(new Status(id, name, desc));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("Name or description is invalid");
		}
	}

	/**
	 * Attempts to modify the name of a status in the database.
	 * 
	 * @param id
	 *            - the id of the status
	 * @param name
	 *            - the name of the status
	 * 
	 * @return Returns true if modification was successful. Otherwise, returns
	 *         false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeStatusName(int id, String name)
			throws IllegalStateException, IllegalArgumentException {

		Status temp = getStatus(id);

		if (temp != null) {
			return changeStatus(id, name, temp.description);
		} else {
			return false;
		}
	}

	/**
	 * Attempts to modify the description of a status in the database.
	 * 
	 * @param id
	 *            - the id of the status
	 * @param desc
	 *            - the description of the status
	 * 
	 * @return Returns true if modification was successful. Otherwise, returns
	 *         false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeStatusDesc(int id, String desc)
			throws IllegalStateException, IllegalArgumentException {

		Status temp = getStatus(id);

		if (temp != null) {
			return changeStatus(id, temp.name, desc);
		} else {
			return false;
		}
	}

	// ////////////////////////////////////////////
	//
	// Shipping Information
	//
	// ////////////////////////////////////////////

	/**
	 * Attempts to modify shipping information to the database. This method can
	 * not be used to change a specimen package. To add items to a shipping
	 * information, please use the addItemsToSpec method. To update the specimen
	 * use the changeSpecimenInfo method.
	 * 
	 * @param barcode
	 *            - a barcode used to identify the specimen. SHOULD NOT BE
	 *            MODIFIABLE BY END USER.
	 * @param username
	 *            - the username of the person adding the specimen info
	 * @param dest
	 *            - an id representing a client site destination
	 * @param status
	 *            - an id representing a status type
	 * @param cour
	 *            - the username of the courier to be assigned
	 * 
	 * @returns Returns true if the modification to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if there is an invalid argument
	 */
	public static boolean changeShippingInformation(String barcode,
			String username, int dest, int status, String cour)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		if (noNulls(username, getUser(username), getClientSite(dest))
				&& !barcode.isEmpty()) {
			try {
				Courier c_temp = getCourierInfo(cour);
				ShippingInformation temp = getShippingInfo(barcode);
				Status newStatus = getStatus(status);

				if (!noNulls(newStatus)) {
					throw new IllegalArgumentException(
							"Invalid barcode or courier");
				}

				dbConnection.changeRecord(new ShippingInformation(
						temp.specimen, getUser(username), getClientSite(dest),
						newStatus, c_temp));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException(
					"Null strings detected, ivalid username/destination or "
							+ "barcode is less than 1.");
		}
	}

	/**
	 * Attempts to modify the shipper associated to the shipping information.
	 * 
	 * @param barcode
	 *            - the barcode associated to the shipping information
	 * 
	 * @param username
	 *            - the username of the new shipper
	 * 
	 * @return Returns true if modification was successful. Otherwise, false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeShippingInformationShipper(String barcode,
			String username) throws IllegalStateException,
			IllegalArgumentException {

		ShippingInformation temp = getShippingInfo(barcode);

		if (temp != null) {
			return changeShippingInformation(barcode, username,
					temp.destination.client_id, temp.status.status_id,
					temp.courier.user.username);
		} else {
			return false;
		}
	}

	/**
	 * Attempts to modify the destination associated to the shipping
	 * information.
	 * 
	 * @param barcode
	 *            - the barcode associated to the shipping information
	 * 
	 * @param destination
	 *            - the new destination of the package
	 * 
	 * @return Returns true if modification was successful. Otherwise, false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeShippingInformationDestination(String barcode,
			int dest) throws IllegalStateException, IllegalArgumentException {

		ShippingInformation temp = getShippingInfo(barcode);

		if (temp != null) {
			return changeShippingInformation(barcode, temp.shipper.username,
					dest, temp.status.status_id, temp.courier.user.username);
		} else {
			return false;
		}
	}

	/**
	 * Attempts to modify the courier associated to the shipping information.
	 * 
	 * @param barcode
	 *            - the barcode associated to the shipping information
	 * 
	 * @param courier
	 *            - the new courier assigned to the package
	 * 
	 * @return Returns true if modification was successful. Otherwise, false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeShippingInformationCourier(String barcode,
			String cour) throws IllegalStateException, IllegalArgumentException {

		ShippingInformation temp = getShippingInfo(barcode);

		if (temp != null) {
			return changeShippingInformation(barcode, temp.shipper.username,
					temp.destination.client_id, temp.status.status_id, cour);
		} else {
			return false;
		}
	}

	// ////////////////////////////////////////////
	//
	// Specimen Info
	//
	// ////////////////////////////////////////////

	/**
	 * Attempts to modify a specimen in the database. Use this to update
	 * existing specimen data.
	 * 
	 * @param barcode
	 *            - the barcode of the Specimen being modified. SHOULD NOT BE
	 *            MODIFIABLE BY THE END USER.
	 * @param desc
	 *            - the description of the Specimen
	 * @param requirements
	 *            - the requirements of shipping for the Specimen
	 * @param contents
	 *            - the contents of the Specimen
	 * 
	 * @returns Returns true if the addition to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if there is an invalid argument
	 */
	public static boolean changeSpecimenInfo(String barcode, String desc,
			String requirements, Map<Integer, List<String>> items)
			throws IllegalStateException, IllegalArgumentException {
		noConnection();

		// TODO : change Map<Integer, List<String>>

		Collection<Item> temp = new LinkedList<Item>();

		for (Integer i : items.keySet()) {
			temp.add(new Item(i, items.get(i).get(0), items.get(i).get(1)));
		}

		if (noNulls(desc, requirements) && !barcode.isEmpty()
				&& !temp.isEmpty()) {
			try {
				dbConnection.changeRecord(new Specimen(barcode, desc,
						requirements, temp));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("Description or requirements"
					+ "is empty");
		}
	}

	// ////////////////////////////////////////////
	//
	// User
	//
	// ////////////////////////////////////////////

	/**
	 * Attempts to modify a user to the database.
	 * 
	 * @param username
	 *            - The username of the person being added. SHOULD NOT BE
	 *            MODIFIABLE BY END USER.
	 * @param password
	 *            - The password associated to the username
	 * @param first
	 *            - The first name of the person
	 * @param last
	 *            - The last name of the person
	 * @param site_id
	 *            - A client site that the person is assigned to
	 * @param type_id
	 *            - A user type regarding the person's privileges
	 * 
	 * @returns Returns true if the modification to the database was successful.
	 *          Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if the arguments are not valid such as being null
	 */
	public static boolean changeUser(String username, String password,
			String first, String last, int site_id, int type_id)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		ClientSite cs = getClientSite(site_id);
		UserType type = getUserType(type_id);

		if (noNulls(username, password, first, last, cs, type)
				&& lengthChecker(username, password, first, last)) {

			if (getUser(username) == null) {
				return false;
			}

			try {
				dbConnection.changeRecord(new User(username, password, first,
						last, cs, type));
				if (type.type_id == 5) {
					return addCourier(username, password, first, last, site_id,
							type_id, new LinkedList<Integer>());
				} else if (type.type_id != 5
						&& getCourierInfo(username) != null) {
					return removeCourier(username);
				}
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("One or more of the parameters"
					+ " are invalid. Input must not be empty.");
		}
	}

	/**
	 * Attempts to modify the password of a user.
	 * 
	 * @param username
	 *            - the id of the client site
	 * @param password
	 *            - the new password
	 * 
	 * @return Returns true if modification was successful. Otherwise, false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeUserPassword(String username, String password)
			throws IllegalStateException, IllegalArgumentException {

		User temp = getUser(username);

		if (temp != null) {
			return changeUser(username, password, temp.fname, temp.lname,
					temp.site.client_id, temp.type.type_id);
		} else {
			return false;
		}
	}

	/**
	 * Attempts to modify the first and last name of a user.
	 * 
	 * @param username
	 *            - the id of the client site
	 * @param fname
	 *            - first name of the user
	 * @param lname
	 *            - last name of the user
	 * 
	 * @return Returns true if modification was successful. Otherwise, false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeUserFirstLastName(String username,
			String fname, String lname) throws IllegalStateException,
			IllegalArgumentException {

		User temp = getUser(username);

		if (temp != null) {
			return changeUser(username, temp.password, fname, lname,
					temp.site.client_id, temp.type.type_id);
		} else {
			return false;
		}
	}

	/**
	 * Attempts to modify the client site of a user.
	 * 
	 * @param username
	 *            - the id of the client site
	 * @param cs
	 *            - the new client site associated to the user
	 * 
	 * @return Returns true if modification was successful. Otherwise, false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeUserClientSite(String username, int cs)
			throws IllegalStateException, IllegalArgumentException {

		User temp = getUser(username);

		if (temp != null) {
			return changeUser(username, temp.password, temp.fname, temp.lname,
					cs, temp.type.type_id);
		} else {
			return false;
		}
	}

	/**
	 * Attempts to modify the type of a user.
	 * 
	 * @param username
	 *            - the id of the client site
	 * @param type
	 *            - the new type of the user
	 * 
	 * @return Returns true if modification was successful. Otherwise, false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeUserStatus(String username, int type)
			throws IllegalStateException, IllegalArgumentException {

		User temp = getUser(username);

		if (temp != null) {
			return changeUser(username, temp.password, temp.fname, temp.lname,
					temp.site.client_id, type);
		} else {
			return false;
		}
	}

	// ////////////////////////////////////////////
	//
	// UserType
	//
	// ////////////////////////////////////////////

	/**
	 * Attempts to modify a user type in the database.
	 * 
	 * @param id
	 *            - the id of the user type
	 * @param name
	 *            - the name of the user type
	 * @param desc
	 *            - the description of the user type
	 * 
	 * @return Returns true if modification was successful. Otherwise, returns
	 *         false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeUserType(int id, String name, String desc)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		Status temp = getStatus(id);

		if (noNulls(temp, name, desc) && lengthChecker(name, desc)) {
			try {
				dbConnection.changeRecord(new UserType(id, name, desc));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("Name or description is invalid");
		}
	}

	/**
	 * Attempts to modify the name of a user type in the database.
	 * 
	 * @param id
	 *            - the id of the user type
	 * @param name
	 *            - the name of the user type
	 * 
	 * @return Returns true if modification was successful. Otherwise, returns
	 *         false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeUserTypeName(int id, String name)
			throws IllegalStateException, IllegalArgumentException {

		UserType temp = getUserType(id);

		if (temp != null) {
			return changeUserType(id, name, temp.description);
		} else {
			return false;
		}
	}

	/**
	 * Attempts to modify the description of a user type in the database.
	 * 
	 * @param id
	 *            - the id of the user type
	 * @param desc
	 *            - the description of the user type
	 * 
	 * @return Returns true if modification was successful. Otherwise, returns
	 *         false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean changeUserTypeDesc(int id, String desc)
			throws IllegalStateException, IllegalArgumentException {

		UserType temp = getUserType(id);

		if (temp != null) {
			return changeUserType(id, temp.name, desc);
		} else {
			return false;
		}
	}

	// ----------------------------------------------------------------------------
	// Methods that remove items in the database
	// ----------------------------------------------------------------------------

	/**
	 * Attempts to remove a client site from the database.
	 * 
	 * @param id
	 *            - id of the client site
	 * 
	 * @return Returns true if removal was successful. Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean removeClientSite(int id)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		if (noNulls(getClientSite(id))) {
			try {
				dbConnection.removeRecord(new ClientSite(id, null, null, null,
						null));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("ID is invalid");
		}
	}

	/**
	 * Attempts to remove a courier from the database.
	 * 
	 * @param username
	 *            - the username of the user who is being removed as a courier.
	 *            THIS SHOULD NOT BE MODIFIABLE BY END USER.
	 * 
	 * @return Returns true if removal was successful. Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if one of the parameters are invalid
	 */
	public static boolean removeCourier(String username)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		if (noNulls(username, getCourierInfo(username))) {
			try {
				dbConnection.removeRecord(new Courier(new User(username, null,
						null, null, null, null), null, 0, 0, null));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException(
					"Username is invalid or user is not a courier");
		}
	}

	/**
	 * Attempts to remove a hospital from the database.
	 * 
	 * @param hospital_id
	 *            - id of the hospital being modified. THIS SHOULD NOT BE
	 *            MODIFIABLE BY END USER.
	 * 
	 * @return Returns true if removal was successful. Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if the parameters are invalid
	 */
	public static boolean removeHospital(int hospital_id)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		if (noNulls(getHospital(hospital_id))) {
			try {
				dbConnection
						.removeRecord(new Hospital(hospital_id, null, null));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("ID is invalid");
		}
	}

	/**
	 * Attempts to remove shipping information from the database.
	 * 
	 * @param barcode
	 *            - a barcode used to identify the specimen. SHOULD NOT BE
	 *            MODIFIABLE BY END USER.
	 * 
	 * @return Returns true if removal was successful. Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if there is an invalid argument
	 */
	public static boolean removeShippingInformation(String barcode)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		if (noNulls(barcode, getShippingInfo(barcode))) {
			try {
				dbConnection.changeRecord(getShippingInfo(barcode));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException(
					"Null strings detected, ivalid username/destination or "
							+ "barcode is less than 1.");
		}
	}

	/**
	 * Attempts to remove a status from the database.
	 * 
	 * @param id
	 *            - id of the status to be removed
	 * 
	 * @return Returns true if removal was successful. Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if the parameters are invalid
	 */
	public static boolean removeStatus(int id) throws IllegalStateException,
			IllegalArgumentException {

		noConnection();

		if (noNulls(getStatus(id))) {
			try {
				dbConnection.removeRecord(new Status(id, null, null));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("ID is invalid");
		}
	}

	/**
	 * Attempts to remove a user from the database.
	 * 
	 * @param username
	 *            - The username of the person being added. SHOULD NOT BE
	 *            MODIFIABLE BY END USER.
	 * 
	 * @return Returns true if removal was successful. Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if the arguments are not valid such as being null
	 */
	public static boolean removeUser(String username)
			throws IllegalStateException, IllegalArgumentException {

		noConnection();

		if (noNulls(username, getUser(username))) {
			try {
				dbConnection.removeRecord(new User(username, null, null, null,
						null, null));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("Username is invalid");
		}
	}

	/**
	 * Attempts to remove a user type from the database.
	 * 
	 * @param id
	 *            - id of the user type to be removed
	 * 
	 * @return Returns true if removal was successful. Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 * @throws IllegalArgumentException
	 *             if the parameters are invalid
	 */
	public static boolean removeUserType(int id) throws IllegalStateException,
			IllegalArgumentException {

		noConnection();

		if (noNulls(getUserType(id))) {
			try {
				dbConnection.removeRecord(new UserType(id, null, null));
				return true;
			} catch (SQLException e) {
				logger.info(e.toString());
				return false;
			}
		} else {
			throw new IllegalArgumentException("ID is invalid");
		}
	}

	// -------------------------------------------------------------------------
	//
	// Methods that retrieve information from the database
	//
	// -------------------------------------------------------------------------

	/**
	 * Attempts to retrieve information related to the username and password.
	 * 
	 * @param username
	 *            The username of the person whose information is being looked
	 *            up
	 * @param password
	 *            The password associated to the username
	 * @return Returns the User object associated to the given username and
	 *         password. If no username and/or password combination is in the
	 *         database, returns null.
	 */
	public static User getUserInfo(String username, String password) {
		noConnection();
		if (noNulls(username, password) && lengthChecker(username, password)) {
			return dbConnection.login(username, password);
		} else {
			return null;
		}
	}

	/**
	 * Attempts to retrieve the user type of the given username.
	 * 
	 * @param username
	 *            - the username to be looked up
	 * 
	 * @return Returns the <code>UserType</code> object corresponding to the
	 *         given username, if applicable. Otherwise, returns <code>null
	 *          </code>
	 */
	public static UserType getUserType(String username) {
		noConnection();
		try {
			if (username != null && !username.isEmpty()) {
				return dbConnection.getUserType(username);
			} else {
				return null;
			}
		} catch (SQLException e) {
			logger.info(e.toString());
		}
		return null;
	}

	/**
	 * Attempts to retrieve the courier corresponding to the username.
	 * 
	 * @param username
	 *            - the username to be looked up
	 * 
	 * @return Returns the <code>Courier</code> object corresponding to the
	 *         given username, if applicable. Otherwise, returns <code>null
	 *          </code>
	 */
	public static Courier getCourierInfo(String username) {
		noConnection();
		try {
			if (username != null && !username.isEmpty()) {
				return dbConnection.getCourierByID(username);
			} else {
				return null;
			}
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve the courier corresponding to the username.
	 * 
	 * @param username
	 *            - the username to be looked up
	 * 
	 * @return Returns the <code>Courier</code> object corresponding to the
	 *         given username, if applicable. Otherwise, returns <code>null
	 *          </code>
	 */
	public static List<ClientSite> getRoute(String username) {
		noConnection();
		Courier temp = getCourierInfo(username);
		if (temp != null) {
			return temp.route;
		} else {
			return null;
		}
	}

	/**
	 * Attempts to retrieve the shipping information containing the given bar
	 * code.
	 * 
	 * @param barcode
	 *            - the bar code to be looked up
	 * 
	 * @return Returns the <code>ShippingInformation</code> object corresponding
	 *         to the given username, if applicable. Otherwise, returns
	 *         <code>null</code>
	 */
	public static ShippingInformation getShippingInfo(String barcode) {
		noConnection();
		try {
			if (barcode != null && !barcode.isEmpty()) {
				return dbConnection.getShippingInfoFor(barcode);
			} else {
				return null;
			}
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve the specimen containing the given bar code.
	 * 
	 * @param barcode
	 *            - the bar code to be looked up
	 * 
	 * @return Returns the <code>Specimen</code> object corresponding to the
	 *         given username, if applicable. Otherwise, returns <code>null
	 *          </code>
	 */
	public static Specimen getSpecimen(String barcode) {
		noConnection();
		try {
			if (barcode != null && !barcode.isEmpty()) {
				return dbConnection.getSpecimenByID(barcode);
			} else {
				return null;
			}
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve shipping information from a client site.
	 * 
	 * @param c
	 *            - the ClientSite to be looked up
	 * 
	 * @return Returns a <code>List&lt;ShippingInformation&gt;</code> object
	 *         containing all the shipping information for the given client
	 *         site. Otherwise, returns <code>null</code>
	 */
	public static List<ShippingInformation> specimenFrom(ClientSite c) {
		noConnection();
		try {
			if (c != null) {
				return dbConnection.specimensFrom(c);
			} else {
				return null;
			}
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve shipping information from a client site.
	 * 
	 * @param c
	 *            - the ClientSite to be looked up
	 * 
	 * @return Returns a <code>List&lt;ShippingInformation&gt;</code> object
	 *         containing all the shipping information for the given client
	 *         site. Otherwise, returns <code>null</code>
	 */
	public static List<ShippingInformation> specimensTo(ClientSite c) {
		noConnection();
		try {
			if (c != null) {
				return dbConnection.specimensTo(c);
			} else {
				return null;
			}
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve all shipping information in the database.
	 * 
	 * @return Returns a <code>List&lt;ShippingInformation&gt;</code> object
	 *         containing all the shipping information in the database.
	 *         Otherwise, returns <code>null</code>
	 */
	public static List<ShippingInformation> getAllShippingInformation() {
		noConnection();
		try {
			return dbConnection.getAllShippingInformation();
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve all client sites in the database.
	 * 
	 * @return Returns a <code>List&lt;ClientSite&gt;</code> object containing
	 *         all the client sites in the database. Otherwise, returns
	 *         <code>null</code>
	 */
	public static List<ClientSite> getAllClientSites() {
		noConnection();
		try {
			return dbConnection.getAllClientSites();
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve all couriers in the database.
	 * 
	 * @return Returns a <code>List&lt;Courier&gt;</code> object containing all
	 *         the couriers in the database. Otherwise, returns <code>null
	 *          </code>
	 */
	public static List<Courier> getAllCouriers() {
		noConnection();
		try {
			return dbConnection.getAllCouriers();
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve all hospitals in the database.
	 * 
	 * @return Returns a <code>List&lt;Hospital&gt;</code> object containing all
	 *         the hospitals in the database. Otherwise, returns <code>null
	 *          </code>
	 */
	public static List<Hospital> getAllHospitals() {
		noConnection();
		try {
			return dbConnection.getAllHospitals();
		} catch (SQLException e) {
			logger.warning("Should not error here when getting hospitals");
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve all user types in the database.
	 * 
	 * @return Returns a <code>List&lt;Item&gt;</code> object containing all the
	 *         items in the database. Otherwise, returns <code>null</code>
	 */
	public static List<Item> getAllItems() {
		noConnection();
		try {
			return dbConnection.getAllItems();
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve all specimens in the database.
	 * 
	 * @return Returns a <code>List&lt;Specimen&gt;</code> object containing all
	 *         the specimens in the database. Otherwise, returns <code>null
	 *          </code>
	 */
	public static List<Specimen> getAllSpecimens() {
		noConnection();
		try {
			return dbConnection.getAllSpecimens();
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve all user types in the database.
	 * 
	 * @return Returns a <code>List&lt;UserType&gt;</code> object containing all
	 *         the user types in the database. Otherwise, returns <code>
	 *          null</code>
	 */
	public static List<UserType> getAllUserTypes() {
		noConnection();
		try {
			return dbConnection.getAllUserTypes();
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve all users in the database.
	 * 
	 * @return Returns a <code>List&lt;User&gt;</code> object containing all the
	 *         users in the database. Otherwise, returns <code>null</code>
	 */
	public static List<User> getAllUsers() {
		noConnection();
		try {
			return dbConnection.getAllUsers();
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve all couriers currently in transit.
	 * 
	 * @return Returns a <code>List&lt;Courier&gt;</code> object containing all
	 *         the couriers in transit. Otherwise, returns <code>null
	 *          </code>
	 */
	public static List<Courier> getInTransitCouriers() {
		List<Courier> temp = getAllCouriers();
		List<Courier> inTransit = new LinkedList<Courier>();
		for (Courier x : temp) {
			if (x.longitude != 0.0 && x.latitude != 0.0) {
				inTransit.add(x);
			}
		}
		return inTransit;
	}

	/**
	 * Attempts to retrieve all packages from user.
	 * 
	 * @param user
	 *            - username of shipping
	 * 
	 * @return Return list of ShippingInformation
	 */
	public static List<ShippingInformation> getAllShippingByUser(String user) {
		List<ShippingInformation> ret = new LinkedList<ShippingInformation>();

		if (user != null && !user.isEmpty()) {
			for (ShippingInformation x : getAllShippingInformation()) {
				if (x.shipper.username.toLowerCase().equals(user.toLowerCase())) {
					ret.add(x);
				}
			}
		}

		return ret;
	}

	/**
	 * Attempts to retrieve a check list from the database.
	 * 
	 * @return Returns a CheckListPair if found. Otherwise, returns null.
	 */
	public static CheckListPair getCheckLists() throws IllegalStateException {
		noConnection();
		try {
			return dbConnection.getCheckLists();
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve a user from the database.
	 * 
	 * @param username
	 *            - username of the person to retrieve
	 * 
	 * @return Returns the User associated to the username. Otherwise, returns
	 *         null.
	 * 
	 */
	public static User getUser(String username) {
		try {
			if (username != null && !username.isEmpty()) {
				return dbConnection.getUserByID(username);
			} else {
				return null;
			}
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve a hospital from the database.
	 * 
	 * @param id
	 *            - the id of the hospital
	 * 
	 * @return Returns the Hospital associated to the ID. Otherwise, returns
	 *         null.
	 */
	public static Hospital getHospital(int id) {
		try {
			if (id > 0) {
				return dbConnection.getHospitalByID(id);
			} else {
				return null;
			}
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve a client site from the database.
	 * 
	 * @param id
	 *            - the id of the client site
	 * 
	 * @return Returns the ClientSite associated to the ID. Otherwise, returns
	 *         null.
	 */
	public static ClientSite getClientSite(int id) {
		try {
			if (id > 0) {
				return dbConnection.getClientSiteByID(id);
			} else {
				return null;
			}
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve a user type from the database.
	 * 
	 * @param id
	 *            - the id of the user type
	 * 
	 * @return Returns the UserType associated to the ID. Otherwise, returns
	 *         null.
	 */
	public static UserType getUserType(int id) {
		try {
			if (id > 0) {
				return dbConnection.getUserTypeByID(id);
			} else {
				return null;
			}
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * Attempts to retrieve a status from the database.
	 * 
	 * @param id
	 *            - the id of the status
	 * 
	 * @return Returns the Status associated to the ID. Otherwise, returns null.
	 */
	public static Status getStatus(int id) {
		try {
			if (id > 0) {
				return dbConnection.getStatusByID(id);
			} else {
				return null;
			}
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}
	}

	/**
	 * @deprecated
	 * 
	 *             Retrieves shipping information that is relevant to the user
	 *             based on the parameters used.
	 * 
	 * @param is
	 *            - a variable amount of ints where each int represents the id
	 *            of a Status
	 * 
	 * @return Returns a map where the key is the id of the Status and the value
	 *         is a list of related ShippingInformation to that id.
	 */
	@SuppressWarnings("unchecked")
	public static Map<Integer, List<ShippingInformation>> getReleveantInfo(
			int... is) {

		Map<Integer, List<ShippingInformation>> status = new HashMap<Integer, List<ShippingInformation>>();
		List<ShippingInformation>[] storage = (List<ShippingInformation>[]) new LinkedList[is.length];
		int[] sortedInput = is.clone();

		Arrays.sort(sortedInput);
		for (int i = 0; i < storage.length; i++) {
			storage[i] = new LinkedList<ShippingInformation>();
		}

		for (ShippingInformation x : getAllShippingInformation()) {
			for (int i = 0; i < is.length; i++) {
				if (sortedInput[i] == x.status.status_id) {
					storage[i].add(x);
					break;
				}
			}
		}

		for (int i = 0; i < storage.length; i++) {
			status.put(sortedInput[i], storage[i]);
		}

		return status;
	}

	/**
	 * Attempts to retrieve all packages that are marked as "In Transit" or
	 * "Waiting" to be picked up.
	 * 
	 * @return Returns a <code>List&lt;ShippingInformation&gt;</code> object
	 *         containing all the packages that are in transit or yet to be
	 *         picked up. Otherwise, returns <code>null</code>
	 */
	public static List<ShippingInformation> getCurrentPackages() {
		noConnection();
		try {
			return dbConnection.getNotArrived();
		} catch (SQLException e) {
			logger.info(e.toString());
			return null;
		}

	}

	/**
	 * Attempts to retrieve all specimens assigned to the given username.
	 * 
	 * @param username
	 *            - username to be looked up for specimens
	 * 
	 * @return Returns a <code>List&lt;ShippingInformation&gt;</code> object
	 *         containing all the packages that are associated to the given
	 *         username. Otherwise, returns <code>null</code>
	 */
	public static List<ShippingInformation> getAllSpecimensByUsername(
			String username) {
		return getAllSpecHelper(username, true);
	}

	/**
	 * Attempts to retrieve all specimens assigned to the given name.
	 * 
	 * @param name
	 *            - name to be looked up for specimens
	 * 
	 * @return Returns a <code>List&lt;ShippingInformation&gt;</code> object
	 *         containing all the packages that are associated to the given
	 *         name. Otherwise, returns <code>null</code>
	 */
	public static List<ShippingInformation> getAllSpecimensByName(String name) {
		return getAllSpecHelper(name, false);
	}

	/**
	 * Changes the status of a shipment to "Arrived"
	 * 
	 * @param barcode
	 *            - the barcode of the shipment
	 * 
	 * @return Returns true if change was successful. Otherwise, returns false.
	 */
	public static boolean arrived(String barcode) {

		ShippingInformation temp = getShippingInfo(barcode);

		if (noNulls(barcode, temp)) {
			changeShippingInformation(barcode, temp.shipper.username,
					temp.destination.client_id, 3, temp.courier == null ? ""
							: temp.courier.user.username);
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Attempts to retrieve the starting check list from the database.
	 * 
	 * @return Returns the starting check list if successful. Otherwise, null.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 */
	public static List<String> getStartingList() throws IllegalStateException {
		CheckListPair temp = getCheckLists();
		if (temp == null) {
			return null;
		} else {
			return getCheckLists().startingList;
		}
	}

	/**
	 * Attempts to retrieve the ending check list from the database.
	 * 
	 * @return Returns the ending check list if successful. Otherwise, null.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 */
	public static List<String> getEndingList() {
		CheckListPair temp = getCheckLists();
		if (temp == null) {
			return null;
		} else {
			return getCheckLists().endingList;
		}
	}

	// -------------------------------------------------------------------------
	//
	// Android server specific
	//
	// -------------------------------------------------------------------------

	/**
	 * Retrieves a list of client site that have packages.
	 * 
	 * @param username
	 *            - username of the courier to be looked up
	 * 
	 * @return Returns a list of client sites that have packages.
	 */
	public static Route getRouteWithPackages(String username) {

		List<ClientSite> newCS = new LinkedList<ClientSite>();

		if (username != null) {
			List<ClientSite> temp = getRoute(username);
			if (temp != null) {
				for (ClientSite x : temp) {
					List<ShippingInformation> s = specimenFrom(x);
					if (s != null && !s.isEmpty()) {
						newCS.add(x);
					}
				}
			}
		}
		return new Route(newCS);
	}

	/**
	 * Attempts to update the GPS of a courier.
	 * 
	 * @param username
	 *            - username of the courier
	 * @param latitude
	 *            - latitude of the courier
	 * @param longitude
	 *            -longitude of the courier
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 */
	public static void updateGPS(String username, double latitude,
			double longitude) throws IllegalStateException {

		noConnection();

		if (noNulls(username, getCourierInfo(username))) {
			Courier temp = getCourierInfo(username);
			try {
				dbConnection.changeRecord(new Courier(temp.user, temp.route,
						latitude, longitude, temp.nextDest));
			} catch (SQLException e) {
				logger.info(e.toString());
			}
		} else {
			logger.info("GPS Update failed: username or courier is null");
		}

	}

	/**
	 * Changes the status of a shipment to "Picked Up."
	 * 
	 * @param barcode
	 *            - the barcode of the shipment
	 * 
	 * @return Returns true if change was successful. Otherwise, returns false.
	 * 
	 * @throws IllegalStateException
	 *             if the there is no connection to the database
	 */
	public static boolean pickedUp(String barcode, String username)
			throws IllegalStateException {
		if (noNulls(barcode, getShippingInfo(barcode))) {
			ShippingInformation temp = getShippingInfo(barcode);
			changeShippingInformation(barcode, temp.shipper.username,
					temp.destination.client_id, 2, username);
			return true;
		} else {
			return false;
		}
	}

	// -------------------------------------------------------------------------
	//
	// Helper methods
	//
	// -------------------------------------------------------------------------

	/**
	 * Helper that throws an exception if there is no connection to the
	 * database.
	 */
	private static void noConnection() throws IllegalStateException {
		if (dbConnection == null) {
			throw new IllegalStateException("Connection to the database"
					+ "has not bee made");
		}
	}

	/**
	 * @deprecated Deprecated method that checks to see if courier is at
	 *             nextDest.
	 */
	@SuppressWarnings("unused")
	private static boolean checkLoc(Courier courier, ClientSite specLoc) {
		return courier.route.indexOf(courier.nextDest) <= courier.route
				.indexOf(specLoc);
	}

	/**
	 * Get specimen of certain couriers based on either their username or first
	 * name.
	 */
	private static List<ShippingInformation> getAllSpecHelper(String s,
			boolean username) {
		List<ShippingInformation> temp = new LinkedList<ShippingInformation>();

		if (s != null && !s.isEmpty()) {
			for (ShippingInformation x : getAllShippingInformation()) {
				if ((username && x.courier.user.username.equals(s))
						|| (!username && x.courier.user.fname.equals(s))) {
					temp.add(x);
				}
			}
		}
		return temp;
	}

	/**
	 * Helper that checks to make sure length of strings aren't 0.
	 */
	private static boolean lengthChecker(String... strings) {
		for (int i = 0; i < strings.length; i++) {
			if (strings[i].isEmpty()) {
				return false;
			}
		}
		return true;
	}
}